package br.com.puertorico.mecanismos.ui.scopes;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import br.com.puertorico.common.loggin.Logger;
import br.com.puertorico.mecanismos.ui.utils.FacesUtils;

@SuppressWarnings("unchecked")
public class ConversationScope implements Scope {

	private static final Logger LOGGER = Logger
			.getLogger(ConversationScope.class);

	private static final String NAVIGATION_MAP;

	private static final String CONVERSATION_MBEANS;

	static {
		NAVIGATION_MAP = "navigationMap";
		CONVERSATION_MBEANS = "exemplojsf2.conversacao.ConversacaoAtual";
	}

	public Object get(String name, ObjectFactory<?> objectFactory) {
		Object obj = objectFactory.getObject();

		Conversation conversation = obj.getClass().getAnnotation(
				Conversation.class);

		if (conversation == null) {
			throw new IllegalArgumentException(
					"O MBean precisa ter a anotacao @Conversation");
		}

		String currentViewId = FacesUtils.getFacesContext().getViewRoot()
				.getViewId();

		for (String viewId : conversation.viewIds()) {
			if (getNavigationMap().containsKey(viewId.trim())) {
				if (getNavigationMap().get(viewId).equals(currentViewId)) {
					if (!getConversationMBeans().containsKey(conversation.id())) {
						getConversationMBeans().put(conversation.id(), obj);
					}
					return getConversationMBeans().get(conversation.id());
				}
			}
		}

		return obj;
	}

	public Object remove(String name) {
		Object obj = getConversationMBeans().remove(name);
		return obj;
	}

	public void registerDestructionCallback(String name, Runnable callback) {
	}

	public Object resolveContextualObject(String key) {
		return null;
	}

	public String getConversationId() {
		return null;
	}

	private static void buildNavigationMap() {
		ServletContext context = FacesUtils.getServletContext();
		if (context.getAttribute(NAVIGATION_MAP) != null) {
			return;
		}
		// extrair as navegacoes
		String navigationFiles = context
				.getInitParameter("com.ocpsoft.pretty.CONFIG_FILES");
		if (navigationFiles == null) {
			navigationFiles = "/WEB-INF/pretty-config.xml";
		}
		Map<String, String> navigationMap = new HashMap<String, String>();
		for (String arquivo : navigationFiles.split(",")) {
			extractNavigationCases(context.getResourceAsStream(arquivo),
					navigationMap);
		}
		context.setAttribute(NAVIGATION_MAP, navigationMap);
	}

	public static Map<String, String> getNavigationMap() {
		buildNavigationMap();
		return (Map<String, String>) FacesUtils.getServletContext()
				.getAttribute(NAVIGATION_MAP);
	}

	private static void extractNavigationCases(InputStream inputStream,
			Map<String, String> mapa) {
		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(inputStream);
			doc.getDocumentElement().normalize();
			if (!doc.hasChildNodes()) {
				return;
			}
			NodeList urlMappingList = doc.getElementsByTagName("url-mapping");
			for (int i = 0; i < urlMappingList.getLength(); i++) {
				Node urlMapping = urlMappingList.item(i);
				if (urlMapping.getNodeType() == Node.ELEMENT_NODE) {
					Element element = (Element) urlMapping;
					String id = element.getAttribute("id");

					NodeList viewIdList = element
							.getElementsByTagName("view-id");
					Element viewId = (Element) viewIdList.item(0);
					mapa.put(id, viewId.getFirstChild().getTextContent());
				}
			}
		} catch (Exception e) {
			LOGGER.error(e);
		}
	}

	public static Map<String, Object> getConversationMBeans() {
		Map<String, Object> conversationMBeans = (Map<String, Object>) FacesUtils
				.getSessionScope().getAttribute(CONVERSATION_MBEANS);
		if (conversationMBeans == null) {
			conversationMBeans = new HashMap<String, Object>();
			FacesUtils.getSessionScope().setAttribute(CONVERSATION_MBEANS,
					conversationMBeans);
		}
		return conversationMBeans;
	}

}